/*
 * Copyright (C) 2010 Fores Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package jp.fores.midori.server;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jp.fores.midori.server.container.Container;

/**
 * ThreadLocalを使って、リクエストやレスポンスなどをスレッドごとに独立して保持するためのクラス。<br>
 * (このクラスの全てのメソッドはスレッドセーフです。)<br>
 */
public class WebContext {
	//==========================================================
	//フィールド

	//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	//クラスフィールド

	/**
	 * 自分自身のインスタンスを管理するためのThreadLocal変数
	 */
	protected static final ThreadLocal<WebContext> threadLocal = new ThreadLocal<WebContext>();


	//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	//インスタンスフィールド

	/**
	 * リクエスト
	 */
	public final HttpServletRequest request;

	/**
	 * レスポンス
	 */
	public final HttpServletResponse response;

	/**
	 * サーブレットコンテキスト
	 */
	public final ServletContext servletContext;

	/**
	 * コンテナ
	 */
	public final Container container;


	//==========================================================
	//メソッド


	//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	//コンストラクタ

	/**
	 * コンストラクタです。<br>
	 * (外部から直接インスタンスを生成できないようにするため、protectedにしています。)<br>
	 *
	 * @param request リクエスト
	 * @param response レスポンス
	 * @param servletContext サーブレットコンテキスト
	 * @param container コンテナ
	 */
	protected WebContext(HttpServletRequest request,
			HttpServletResponse response, ServletContext servletContext,
			Container container) {
		//==========================================================
		//引数の値をフィールドに設定する

		//リクエスト
		this.request = request;

		//レスポンス
		this.response = response;

		//サーブレットコンテキスト
		this.servletContext = servletContext;

		//コンテナ
		this.container = container;
	}


	//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	//クラスメソッド

	/**
	 * 新たなインスタンスを生成して、ThreadLocalに登録します。<br>
	 * このインスタンスはスレッドごとに独立しています。<br>
	 * (外部のパッケージから呼び出されたくないので、protectedにしています。)<br>
	 *
	 * @param request リクエスト
	 * @param response レスポンス
	 * @param servletContext サーブレットコンテキスト
	 * @param container コンテナ
	 * @return このクラスのインスタンス
	 */
	protected static WebContext createInstance(HttpServletRequest request,
			HttpServletResponse response, ServletContext servletContext,
			Container container) {
		//自分自身のクラスのインスタンスを生成
		WebContext selfInstance = new WebContext(request, response, servletContext, container);

		//生成したインスタンスをThreadLocal変数に登録
		threadLocal.set(selfInstance);

		//生成したインスタンスを返す
		return selfInstance;
	}

	/**
	 * このクラスのインスタンスをThreadLocalから削除します。<br>
	 * (外部のパッケージから呼び出されたくないので、protectedにしています。)<br>
	 */
	protected static void clear() {
		//ThreadLocal変数の値を削除する
		threadLocal.remove();
	}

	/**
	 * このクラスのインスタンスをThreadLocalから取得します。<br>
	 * このインスタンスはスレッドごとに独立しています。<br>
	 *
	 * @return このクラスのインスタンス
	 * @throws IllegalStateException インスタンスが生成されていない、またはすでにクリアされている場合
	 */
	public static WebContext getInstance() throws IllegalStateException {
		//自分自身のクラスのインスタンスをThreadLocal変数から取得
		WebContext selfInstance = threadLocal.get();

		//取得できなかった場合
		if (selfInstance == null) {
			//例外を投げる
			throw new IllegalStateException("インスタンスが生成されていない、またはすでにクリアされています。");
		}

		//取得したインスタンスを返す
		return selfInstance;
	}

}
